package hcs;


import hcs.interfaces.ClockObserver;
import hcs.interfaces.IHouseSettings;
import hcs.model.Boiler;
import hcs.model.Clock;
import hcs.model.Environment;
import hcs.model.Room;
import hcs.settings.DefaultHouseSettings;
import hcs.settings.HouseSettings;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import stubs.*;

/**
 * The class which is responsible of the creation of
 * {@link Room} and {@link Environment}. It resister on {@link Clock} to poll
 * the rooms and force them to update their state.
 *  <br>
 *  Build {@link Room} and {@link Environment} istances by using:
 * <ul> 
 * <li>information collected in the {@link DefaultHouseSettings} object.
 * <li> {@link PhysicalFactory} provided during deployment stage
 * </ul>
 */
public class HouseController implements Iterable<Room>, ClockObserver {
	private Environment environment;
	private List<Room> rooms;
	private Clock clock;
	private IHouseSettings houseSettings;
	private Boiler boiler;
	
	/**
	 * Class constructor.
	 */
	public HouseController() {
		/* Environement */
		environment = new Environment();
		
		/* Rooms */
		rooms = new LinkedList<Room>();
		houseSettings = HouseSettings.getHouseSettings();
		String[] names = houseSettings.getRoomNames();
		int[] sqm = houseSettings.getSqm();
		for(int i= 0; i < sqm.length; i++) {
			IPhysicalRoom r = PhysicalFactory.getPhysicalRoom(names[i], sqm[i]);
			assert r != null;
			rooms.add(new Room(names[i], sqm[i],r, this));
		}
		
		/* Bioler */
		boiler = new Boiler();
		computeBoilerTemperature();
		
		/* Start observing the clock */
		this.clock = Clock.getInstance();
		clock.addObserver(this);
	}
	
	/**
	 * Compute the required boiler temperature for the current
	 * room heating temperatures.
	 *
	 */
	private void computeBoilerTemperature() {
		double maxTemp = 0;
		Iterator<Room> allRooms = this.iterator();
		while (allRooms.hasNext()) {
			Room aRoom = allRooms.next();
			if (aRoom.getHeaterTarget() > maxTemp) {
				maxTemp = aRoom.getHeaterTarget();
			}
		}
		boiler.setTargetTemperature(maxTemp);
	}

	/**
	* @return {@link Environment} object
	 */
	public Environment getEnvironment() {
		return this.environment;
	}
	
	/**
	* @return {@link Clock} object
	 */
	public Clock getClock() {
		return this.clock;
	}

	/**
	 * @return {@link Iterator} across {@link Room}
	 */
	public Iterator<Room> iterator() {
		return this.rooms.iterator();
	}
	
	/**
	 * @return number of {@link Room}
	 */
	public int getNumberOrRooms() {
		return rooms.size();
	}
	
	/**
	 * 
	 * @return current {@link DefaultHouseSettings}
	 */
	public IHouseSettings getHouseSettings() {
		return this.houseSettings;
	}

	public void update(Observable o, Object arg) {
		// call the poll method on each room, then compute the boiler temperature
		Iterator<Room> allRooms = this.iterator();
		while (allRooms.hasNext()) {
			Room aRoom = allRooms.next();
			aRoom.poll();
		}
		computeBoilerTemperature();
	}
	
	/**
	 * Add the </code>Observer o</code> to the observers of the boiler.
	 * <p>
	 * The method <code>update()</code> on <code>o</code> will be called whenever the boiler temperature changes. 
	 * @param o the object observing the boiler.
	 */
	public void addBoilerObserver(Observer o) {
		boiler.addObserver(o);
	}
	/**
	 * Remove </code>Observer o</code> from the observers of the boiler.
	 */
	public void deleteBoilerObserver(Observer o) {
		boiler.deleteObserver(o);
	}
}